
class Cloud extends Entity {

// PARAMETERS
  final int initNumMemes = 60;

  // size of cloud box (pixels)
  final float sizeX = 1500;
  final float sizeY = 200;

  final float maxVelocity = 0.8;

  final float probOfMemeDirChange = 0.01;

  final float minSpreadBonus = 0.3;
  final float maxSpreadBonus = 0.6;
// END PARAMETERS

// MEMBERS
  Vector memes;
  ParticleSystem cloudSystem;
  final float marginLeft = 0;

  // boundaries for the "bouncing box"
  Entity boxTopLeft, boxBottomRight;
// END MEMBERS

  public Cloud() {
    super();

    // dont skip drawing the cloud
    alwaysDraw = true;

    cloudSystem = new ParticleSystem(0, 0.91);

    size = 500.0;

    // create cloud centerpoint
    p = cloudSystem.makeParticle( 
        size, 0, cloudLevel, 0);

    p.makeFixed();

    // make two particles that make up a bouncing box
    boxTopLeft = new Entity();
    boxBottomRight = new Entity();

    boxTopLeft.p = cloudSystem.makeParticle( 
      size, absx() - sizeX/2, absy() - sizeY/2 , 0);
    boxTopLeft.p.makeFixed();
     
    boxBottomRight.p = cloudSystem.makeParticle( 
      size, absx() + sizeX/2, absy() + sizeY/2, 0);
    boxBottomRight.p.makeFixed();
    
    memes = new Vector();

    // create memes within the cloud box

    for(int i=0; i < initNumMemes; i++) 
      spawnMeme();
  }

  private void spawnMeme() {
    Meme spawn = new Meme();

    spawn.p = cloudSystem.makeParticle(spawn.size, 
        boxTopLeft.absx() + random(sizeX), 
        boxTopLeft.absy() + random(sizeY), 
        0);

    spawn.p.setVelocity(
        random(-maxVelocity, maxVelocity),
        random(-maxVelocity, maxVelocity), 0);

    spawn.cloudPuller = cloudSystem.makeSpring(
        p, spawn.p, 0.02, 0.9, 
        1.0);
    
    spawn.cloudPuller.turnOff();

    spawn.spreadBonus = fixedRandom(minSpreadBonus,
        maxSpreadBonus);

    memes.add(spawn);
  }

  public Meme getMeme() {
    if(memes.size() < 1) spawnMeme();

    Meme pick = (Meme)memes.get((int)fixedRandom(memes.size()));
    return pick;
  }

  public void takeBack(Meme meme, Individual from) {
    memes.add(meme);
    // meme.pullBack();
  }

  public void update() {

    cloudSystem.advanceTime(timeScale);

    // bounce inside box
    float vx, vy, px, py;

    for(int i=0; i<memes.size(); i++) {
      Meme m = (Meme)memes.get(i);
      px = m.absx();
      py = m.absy();

      // randomize movement if inside the box
      if(py < boxBottomRight.absy()) {
        if(random(1) < probOfMemeDirChange)
          m.p.setVelocity(
            random(-maxVelocity, maxVelocity),
            random(-maxVelocity, maxVelocity), 0);
      }

      vx = m.p.velocity().x();
      vy = m.p.velocity().y();

      // turn off the spring when the meme is pulled back
      if(m.cloudPuller.isOn() && 
        (m.absy() < boxBottomRight.absy()) &&
        (m.absy() > boxTopLeft.absy()) && 
        (m.absx() < boxBottomRight.absx()) &&
        (m.absx() > boxTopLeft.absx())) {
        m.cloudPuller.turnOff();
      }

      if((py < boxTopLeft.absy()) && (vy < 0) ||
          (py > boxBottomRight.absy()) && (vy > 0))
          m.p.setVelocity(vx, vy * -1, 0);

      if(((px < boxTopLeft.absx()) && vx < 0) ||
        ((px > boxBottomRight.absx()) && vx > 0))
          m.p.setVelocity(vx * -1, vx, 0);
    }

  }

  public void drawMacro() {

    for(int i = 0; i < memes.size(); i++) {
      Meme m = (Meme)memes.get(i);
      m.drawMacro();
    }

    stroke(255);

    /*
    float bt = boxTopLeft.y();
    float bb = boxBottomRight.y();
    float bl = boxTopLeft.x();
    float br = boxBottomRight.x();

    line(bl, bt, br, bt);
    line(bl, bt, bl, bb);
    line(br, bt, br, bb);
    line(br, bb, bl, bb);

    fill(0, 255, 0);
    ellipse(x(), y(), 10, 10);
    */

  }

  public void drawMicro() {
    drawMacro();// dont draw cloud in microMode
  }


}
